﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Soundteller.Audio.Model;
using Soundteller.Audio.Model.Interfaces;
using Soundteller.Audio.Repositories;
using Soundteller.Audio.Repositories.Interfaces;
using Soundteller.Common.Tests;

namespace Soundteller.Audio.Tests.Unit.Repositories.SongRepositorySpecifications
{
    public abstract class WhenUpdate : TestBase
    {
        protected ISongRepository SongRepository { get; private set; }
        protected Mock<IMemoryContext> Context { get; private set; }
        protected List<Song> SongsInRepository { get; set; }
        protected abstract Song SongToUpdate { get; }

        protected override void Arrange()
        {
            SongsInRepository = new List<Song>();

            Context = new Mock<IMemoryContext>();
            Context.Setup(c => c.Songs).Returns(SongsInRepository);

            SongRepository = new SongRepository(Context.Object);
        }

        protected override void Act()
        {
            SongRepository.Update(SongToUpdate);
        }       
    }

    [TestClass]
    public class WhenUpdateGivenSongIsEmpty : WhenUpdate
    {
        protected override Song SongToUpdate
        {
            get { return (Song)null; }
        }

        protected override void Act()
        {
            ExpectException(() => base.Act());
        }

        [TestMethod]
        public void ThenAnArgumentNullExceptionShouldBeThrown()
        {
            Exception.VerifyArgumentNullException("song");
        }
    }

    [TestClass]
    public class WhenUpdateGivenSongIsUnknown : WhenUpdate
    {
        protected override Song SongToUpdate
        {
            get { return new Song(); }
        }

        protected override void Act()
        {
            ExpectException(() => base.Act());
        }

        [TestMethod]
        public void ThenAnInvalidOperationExceptionShouldBeThrown()
        {
            Exception.VerifyInvalidOperationException("Song not found");
        }
    }

    [TestClass]
    public class WhenUpdateGivenSongIsKnown : WhenUpdate
    {
        private Song _knownSong = new Song { Id = Guid.NewGuid(), EndBeat = 1 };

        protected override Song SongToUpdate
        {
            get { return _knownSong; }
        }

        protected override void Arrange()
        {
            base.Arrange();

            _knownSong.EndBeat = 13;
            SongsInRepository.Add(_knownSong);
        }

        [TestMethod]
        public void ThenSongShouldBeUpdated()
        {
            Assert.AreEqual(13, _knownSong.EndBeat);
        }
    }
}
